/* Copyright - Apache License 2.0
 * 
 * The project "kyou" is
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.kyou.pack.segment;

import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import net.kyou.exception.KyouErr;
import net.kyou.exception.KyouException;
import net.kyou.pack.PackContext;
import net.kyou.pack.StyleItem;
import net.kyou.util.KyouByteOutputStream;

import org.w3c.dom.Element;

/**
 * 定义组成样式的“段”
 * 
 * @author NuclearG (<a href="mailto:nuclearg@163.com">nuclearg@163.com</a>)
 */
public abstract class Segment {
    /**
     * 各种Segment的实现类的缓存
     */
    private final static Map<String, Class<? extends Segment>> classes = new HashMap<String, Class<? extends Segment>>();
    static {
        init(NullSegment.class);
        
        init(TextSegment.class);
        
        init(IntSegment.class);
        init(StringSegment.class);
        init(BytesSegment.class);
        
        init(FloatSegment.class);
        init(BCDSegment.class);
        init(BackspaceSegment.class);
    }

    /**
     * 从XML中初始化一个Segment实例
     * 
     * @param e
     *            XML节点
     * @param encoding
     *            StyleSpecification中指定的报文整体编码
     * @param style
     *            该文本段隶属于的组包样式单元
     * @return 根据XML建立的Segment实例
     */
    public static Segment __new(Element e, Charset encoding, StyleItem style) {
        try {
            String tag = e.getNodeName();
            if (classes.containsKey(tag))
                try {
                    return (Segment) classes.get(tag).getDeclaredConstructors()[0].newInstance(e, encoding, style);
                } catch (InvocationTargetException ex) {
                    throw ex.getCause();
                }

            throw new KyouException(KyouErr.Style.InvalidSegmentTag, tag);
        } catch (Throwable ex) {
            throw new KyouException(KyouErr.Style.InitSegmentFail, ex);
        }
    }

    /**
     * 初始化一个文本段实例
     * 
     * @param text
     *            文本
     * @param encoding
     *            StyleSpecification中指定的报文整体编码
     * @param style
     *            该文本段隶属于的组包样式单元
     * @return 建立的文本段实例
     */
    public static Segment __text(String text, Charset encoding, StyleItem style) {
        return new TextSegment(text, encoding, style);
    }

    /**
     * 工具函数 将一个Segment实现类的信息写入缓存
     */
    private static void init(Class<? extends Segment> cls) {
        SegmentTag tag = cls.getAnnotation(SegmentTag.class);
        classes.put(tag.name(), cls);
    }

    /**
     * 本段隶属于的组包样式单元
     */
    public final StyleItem style;

    /**
     * 初始化一个Segment
     */
    Segment(StyleItem style) {
        this.style = style;
    }

    /**
     * 导出该段对应的字节
     * 
     * @param context
     *            组包上下文
     */
    public abstract void __export(PackContext context, KyouByteOutputStream s);
}
